<?php declare(strict_types=1);
namespace hi;
use think\facade\Db;
class Annex {
    protected static $error;
    protected $tb = '';
    protected $tb_group = '';
    public static $group;
    /**
     * 资源表操作
     * @group 资源分组, 格式如  m_member/p_devhelp
     * @tb 资源表
     * @tb_group 资源表统计表
     */
    public function __construct($group, $tb, $tb_group)
    {
        $this->tb = $tb;
        $this->tb_group = $tb_group;
        self::$group = $group;
    }

    /**
     * 写入资源表
     * @param string 地址值
     * @type string 储存类型, 分为 image/file/video
     * @saveDir string 自定义储存目录
     * @return int 返回资源ID
     */
    public function save($param, $saveDir=null){
        $defRoot = $saveDir !== null ? $saveDir : (config('upload.save_dir') ?: './uploads');
        $annexData = explode('|', $param);
        foreach ($annexData as $kk=>$vv){
            $annexItem = explode('@', $vv);
            $data[$annexItem[0]] = $annexItem[1];
        }
        $rootPath = root_path() . (strpos($defRoot, '..') !== false ? ltrim($defRoot, '.\./') : 'public' . ltrim($defRoot, '.'));
        if(!is_dir($rootPath)){
            @mkdir($rootPath, 0755, true);
        }
        $hasAnnex = Db::name($this->tb)->where(['hash'=>$data['hash']])->find();
        if(null !== $hasAnnex){
            if(!file_exists($hasFilePath = $rootPath . '/' . self::$group . '/' . $data['type'] . '/' . $hasAnnex['file'])){
                $del = $this->del($hasAnnex['id'], $data['type']);
                if(!$del){
                    self::$error = 'picture repeat';
                    return false;
                }
                $id = self::add($data, $data['type'], $saveDir);
            }else{
                $id = $hasAnnex['id'];
            }
        }else{
            $id = self::add($data, $data['type'], $saveDir);
        }
        //删除临时文件
        if(strpos($data['file'], 'temp')){
            $rootTempPath = root_path() . 'public/uploads';
            $tempPath = explode('uploads', $data['file'])[1];
            if(file_exists($tempFile = $rootTempPath . $tempPath)){
                @unlink($tempFile);
            }
        }
        if($id !== false && is_numeric($id)){
            return $id;
        }else{
            self::$error = 'add error';
            return false;
        }
    }

    public function add($data, $type, $saveDir=null){
        $defRoot = $saveDir !== null ? $saveDir : (config('upload.save_dir') ?: './uploads'); //空默认uploads目录
        $rootPath = root_path() . (strpos($defRoot, '..') !== false ? ltrim($defRoot, '.\./') : 'public' . ltrim($defRoot, '.'));
        $rootTempPath = root_path() . 'public/uploads';
        if(!is_dir($rootPath)){
            @mkdir($rootPath, 0755, true);
        }
        $data['annex_type'] = $data['ext'];
        if(strpos($data['file'], 'http') === false){ //带域名的无需解析
            $tempPath = $data['file'];
            $data['file'] = explode($type.'/', $tempPath)[1];
            $data['save_dir'] = strpos($defRoot, '../') !== false ? $defRoot : ($defRoot != './uploads' ? str_replace('./', '', $defRoot) : '');
        }
        $id = Db::name($this->tb)->strict(false)->insertGetId($data);
        $obj = Db::name($this->tb_group);
        $where = ['ext'=>$data['ext']];
        $res = $obj->where(['ext'=>$data['ext']])->find();
        if($res !== null){
            $update['count'] = $res['count'] + 1;
            $update['size'] = $res['size'] + $data['size'];
            $res = $obj->where($where)->update($update);
        }else{
            $res = $obj->insert(['ext'=>$data['ext'], 'count'=>1, 'size'=>$data['size']]);
        }
        Db::commit();
        $tempPath = explode('uploads', $tempPath)[1];
        $destFile = str_replace('temp/' . $type, $type, $tempPath);
        $destDir = pathinfo($destFile,PATHINFO_DIRNAME);
        if(!is_dir($rootPath . $destDir)){
            mkdir($rootPath . $destDir, 0755, true);
        }
        if(file_exists($tempFile = $rootTempPath . $tempPath)){
            copy($tempFile, $rootPath . $destFile);
        }
        return $id;
    }

    public function getFilePath($param){
        if(strpos($param, '|') === false || strpos($param, '@') === false){
            self::$error = 'file path error';
            return false;
        }
        $paths = explode('@', explode('|', $param)[0]);
        return $paths[1];
    }

    /**
     * 查找某个数据字段的资源
     * @param $id string 格式: 'x|annex'/'x,x,x|annex'
     * @return array
     */
    public function first($param){
        $item = explode('|', $param);
        $result = [];
        if(strpos(',', $item[0]) !== false){
            $ids = explode(',', $item[0]);
            foreach ($ids as $v){
                $result[] = Db::name($this->tb)->where(['id'=>$v])->value('file');
            }
        }else{
            $result[] = Db::name($this->tb)->where(['id'=>$item[0]])->value('file');
        }
        return $result;
    }

    /**
     * 检测图片尺寸
     */
    public function checkImgSize($file, $width, $height){
        $image = getimagesize($path = '.'.$file);
        if ($image[0] != $width) {
            self::$error = '图标尺寸长度不符合要求('.$width.'px)';
            return false;
        }
        if($image[1] != $height){
            self::$error = '图标尺寸高度不符合要求('.$height.'px)';
            return false;
        }
        return true;
    }

    /**
     * 检测文件类型
     * @param $ext string|array
     * @return bool
     */
    public function checkFileExt($path, $ext){
        $pathInfo = pathinfo($path);
        if(is_array($ext)){
            if(!in_array($pathInfo['extension'], $ext)){
                self::$error = '文件格式错误';
                return false;
            }
        }else{
            if($ext !== $pathInfo['extension']){
                self::$error = '文件格式错误';
                return false;
            }
        }
        return true;
    }

    /**
     * 获取一个资源数据
     * @param $ext string|array
     * @return bool
     */
    public function get($id, $type){
        $res = Db::name($this->tb)->find($id);
        if($res !== null){
            $rootPath = $res['save_dir'] ?: './uploads';
            if($res['domain']){
                $protocol = $res['protocol'] ? 'https://' : 'http://';
                $src = $protocol.$res['domain'].'/'.$res['file'];
            }else{
                if(strpos($rootPath, '../') !== false){
                    $src = $rootPath . '/'. self::$group . '/' . $type . '/' . $res['file'];
                }else{
                    $src = ltrim($rootPath,".") . '/' . self::$group . '/' . $type . '/' . $res['file'];
                }
            }
            $rootPath = strpos($rootPath, '../') !== false ? str_replace('../', '', $rootPath) : str_replace('.', '', $rootPath);
            $res['file'] = $rootPath . '/' . self::$group.'/'.$type.'/'.$res['file'];
            $val = 'file@'.$res['file'].'|size@'.$res['size'].'|hash@'.$res['hash'].'|type@'.$type.'|ext@'.$res['ext'].'|save_dir@'.$res['save_dir'] .'|group@'.self::$group.'|create_time@'.$res['create_time'];
            if($res['driver'] && $res['domain']){
                $val .= '|driver@'.$res['driver'].'|domain@'.$res['domain'].'|protocol@'.$res['protocol'];
            }
            return [$val, $src];
        }

    }

    /**
     * 删除资源
     * @id 主键值
     * @force 是否真实删除,默认为真实删除
     * @return int
     */
    public function del($id, $type, $force=true){
        $annex = Db::name($this->tb)->where('id', $id)->find();
        if($force === false){
            $res = Db::name($this->tb)->where('id', $id)->useSoftDelete('delete_time', time())->delete();
        }else{
            $res = Db::name($this->tb)->where('id', $id)->delete();
            $rootPath = $annex['save_dir'] ?: './uploads';
            $basePath = root_path() . (strpos($rootPath, '../') !== false ? ltrim($rootPath, '.\./') : 'public/'.ltrim($rootPath, './'));
            $filePath = $basePath . '/' . self::$group . '/' . $type.'/' . $annex['file'];
            if(file_exists($filePath)){
                unlink($filePath);
            }
        }
        if($force === true && $res){
            $data = Db::name($this->tb_group)->where(['ext'=>$annex['ext']])->find();
            $newData['count'] = $data['count'] - 1;
            $newData['size'] = $data['size'] - $annex['size'];
            Db::name($this->tb_group)->where('ext', $data['ext'])->update($newData);
        }
        return true;
    }

    public function getError(){
        return self::$error;
    }

}